feat(studio): split clip at playhead for media elements [7/10]#1189
Conversation
9a94cd9 to
bc87ce5
Compare
0dbfe93 to
925397e
Compare
bc87ce5 to
55d81f3
Compare
925397e to
4711c17
Compare
1670e95 to
6f66981
Compare
4711c17 to
32dd0bb
Compare
6f66981 to
96ccb09
Compare
32dd0bb to
7f991c4
Compare
jrusso1020
left a comment
There was a problem hiding this comment.
Clean focused PR — split a media clip at the playhead. +245/-0. Right-sized scope.
Verify before merge:
1. Media-only guard placement
PR body says "media-only guard" and "Split restricted to media only (video/audio/img)". Two layers needed:
- Server-side (in
splitElementInHtmlor the API endpoint): rejects split requests on non-media elements with a clean 400, not a silent no-op or partial mutation. - Client-side: the right-click menu item +
Sshortcut don't fire on non-media selections.
If only client-side gates, an adversarial / agent caller can still POST a split mutation against a <div> and get unpredictable behavior. Worth checking both layers.
2. Splitting an element with keyframes
splitElementInHtml clones the element and adjusts timing/media-start. For a <video> with no keyframes, this is straightforward. For a media element that's also a GSAP tween target, what happens to the keyframes?
- Cloned element gets a new
id(probably). Existing GSAP tween targets the old id → no longer targets the new clone. Acceptable? Or should the tween split too? - If split happens at t=50% of the clip's window and the keyframes are at 0%/50%/100% of the clip, the post-split clip should arguably retain
50%/100%keyframes (relative) and the pre-split clip should retain0%/50%. Likely out of scope for this PR (PR body says "media-only"), so the keyframe-target divergence is a non-issue — just confirm the documented contract.
3. Edge cases for the S shortcut
- Playhead at clip boundary: split at t=0 or t=clip.duration. Should be a no-op or produce zero-length clips? Test plan worth covering.
- Playhead outside any clip: no-op.
- Multiple clips selected: split applies to all? Just one? Reject?
4. Phosphor Scissors icon
Verify the icon is already in the project's existing icon set (Phosphor is likely already a dep). If this PR adds Phosphor for the first time, the dep addition belongs in the PR description.
Non-blocking
The splitElementInHtml function is now part of the core source mutation surface. If this gets called from agent flows or external consumers, document its semantics in the JSDoc — particularly the "what gets cloned" (style attrs? class attrs? data-* attrs?) contract.
Review by Jerrai (hyperframes specialist)
96ccb09 to
343b43b
Compare
524dc79 to
6186562
Compare
343b43b to
1d95509
Compare
Revert totalTime nudge that caused black first frames in from() tweens. Keep stale CSS offset cleanup. Regenerate baselines for offset cleanup.
…od baselines Baselines regenerated inside Dockerfile.test on the devbox to match the current runtime init.ts changes. Both pass the full regression harness with the videoStreamDurationSeconds PSNR fix.
…ation U1: stripGsapTranslateFromTransform now rotates the offset vector by the element's CSS rotation angle before subtracting from m41/m42. Fixes elements drifting from cursor during drag when rotated. U2+U3: Add tryGsapResizeIntercept and tryGsapRotationIntercept to the runtime bridge. Resize and rotation handle changes now create keyframes via the same async pipeline as position drag. CSS path guards prevent double-persistence for GSAP-animated elements.
CSS compose order is translate → rotate → transform. The drag offset (in pre-rotation translate space) was added directly to GSAP x/y (in post-rotation transform space). Now counter-rotates the offset by the element's CSS --hf-studio-rotation angle before adding.
Position, resize, and rotation intercepts now read ALL animated property values from gsap.getProperty() at commit time and include them in the keyframe. Prevents other properties from jumping to interpolated values between surrounding keyframes when only one property (e.g., width) was explicitly changed.
Revert totalTime nudge that caused black first frames in from() tweens. Keep stale CSS offset cleanup. Regenerate baselines for offset cleanup.
…otkey Add splitElementInHtml to core source mutation helpers — clones an element at the split time, adjusts data-start/data-duration/data-media-start for both halves, and inserts the clone after the original. Wire through: split-element API endpoint, handleTimelineElementSplit in useTimelineEditing, clip context menu (right-click → Split at Xs), toolbar split button, and S keyboard shortcut. Edge cases: locked/implicit clips blocked, media trim offset adjusted by playback rate, unique ID generation with collision avoidance, undo via edit history.
1d95509 to
845b499
Compare
6186562 to
54d1996
Compare

Summary
splitElementInHtmlto core source mutation — clones element, adjusts timing/media-startsplit-elementAPI endpointhandleTimelineElementSplithandler with media-only guardSkeyboard shortcut+245 LOC